package com.samphanie.auiu.library.executor

import android.os.Handler
import android.os.Looper
import androidx.annotation.IntRange
import com.samphanie.auiu.library.log.AuiuLog
import java.util.concurrent.*
import java.util.concurrent.atomic.AtomicLong
import java.util.concurrent.locks.Condition
import java.util.concurrent.locks.ReentrantLock

/**
 * @author ZSY
 *
 * 支持按任务的优先级去执行，支持线程池暂停、恢复（文件批量下载、上传）
 * 支持异步结果主动回调主线程
 * TODO 监控线程池耗时任务、定时、延迟
 */
object AuiuExecutor {

    private const val TAG: String = "AuiuExecutor"
    private var isPaused: Boolean = false
    private var auiuExecutor: ThreadPoolExecutor
    private var lock: ReentrantLock
    private var pauseCondition: Condition
    private val mainHandler = Handler(Looper.getMainLooper())

    init {
        lock = ReentrantLock()
        pauseCondition = lock.newCondition()

        val cpuCount = Runtime.getRuntime().availableProcessors()
        val corePoolSize = cpuCount + 1
        val maxPoolSize = cpuCount * 2 + 1
        val blockingQueue: PriorityBlockingQueue<out Runnable> = PriorityBlockingQueue()
        val keepAliveTime = 30L
        val unit = TimeUnit.SECONDS

        val seq = AtomicLong()
        val threadFactory = ThreadFactory {
            val thread = Thread(it)
            // auiu-executor-0
            thread.name = "auiu-executor-" + seq.getAndIncrement()
            return@ThreadFactory thread
        }

        auiuExecutor = object : ThreadPoolExecutor(
            corePoolSize,
            maxPoolSize,
            keepAliveTime,
            unit,
            blockingQueue as BlockingQueue<Runnable>,
            threadFactory
        ) {
            override fun beforeExecute(t: Thread?, r: Runnable?) {
                if (isPaused) {
                    lock.lock()
                    try {
                        pauseCondition.await()
                    } finally {
                        lock.unlock()
                    }
                }
            }

            override fun afterExecute(r: Runnable?, t: Throwable?) {
                // 监控线程池耗时任务，线程创建数量，正在运行的数量
                AuiuLog.et(TAG, "已执行完的任务的优先级是：" + (r as PriorityRunnable).priority)
            }
        }
    }

    @JvmOverloads
    fun executor(@IntRange(from = 0, to = 10) priority: Int = 0, runnable: Runnable) {
        auiuExecutor.execute(PriorityRunnable(priority, runnable))
    }
    @JvmOverloads
    fun executor(@IntRange(from = 0, to = 10) priority: Int = 0, runnable: Callable<*>) {
        auiuExecutor.execute(PriorityRunnable(priority, runnable))
    }

    abstract class Callable<T> : Runnable {
        override fun run() {
            mainHandler.post { onPrepare() }
            val t = onBackground()
            mainHandler.post { onCompleted(t) }
        }

        open fun onPrepare() {
            // 转菊花
        }

        abstract fun onBackground() : T
        abstract fun onCompleted(t: T)
    }

    class PriorityRunnable(val priority: Int, val runnable: Runnable) : Runnable,
        Comparable<PriorityRunnable> {
        override fun compareTo(other: PriorityRunnable): Int {
            return when {
                this.priority < other.priority -> 1
                this.priority > other.priority -> -1
                else -> 0
            }
        }

        override fun run() {
            runnable.run()
        }

    }

    @Synchronized
    fun pause() {
        isPaused = true
        AuiuLog.et(TAG, "auiuexecutor is paused")
    }

    @Synchronized
    fun resume() {
        isPaused = false
        lock.lock()
        try {
            pauseCondition.signalAll()
        } finally {
            lock.unlock()
        }
        AuiuLog.et(TAG, "auiuexecutor is resume")
    }

}